﻿using System;
using System.Device.Location;
using System.IO;
using System.Linq;
using System.Net;
using System.ServiceModel.Syndication;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using System.Xml;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

namespace Teele
{
    public partial class MainPage : PhoneApplicationPage
    {
        private GeoCoordinateWatcher watcher;
        private GetFile getFile;
        private double? nextSpeedCamDistance;
        private double? previousSpeedCamDistanceValue;
        private bool audibleSpeedCamAlertDone = false;
        private bool GPSTurnedOn = false;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            StreamResourceInfo stream = Application.GetResourceStream(new Uri("kaamerad.xml", UriKind.Relative));
            XmlParser.Parse(stream.Stream);

            this.OrientationChanged += PhoneApplicationPage_OrientationChanged;
            //UpdateOrientation();

            //Download SpeedCam database
            getFile = new GetFile();
            getFile.Run();

            //Updare RSS feed
            updateRSS();

            Uri uri = new Uri("speed-camera.jpg", UriKind.Relative);
            BitmapImage imgSource = new BitmapImage(uri);
            this.image_h.Source = this.image_v.Source = imgSource;

            // The watcher variable was previously declared as type GeoCoordinateWatcher. 
            if (watcher == null)
            {
                watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); // using high accuracy
                watcher.MovementThreshold = 0; // use MovementThreshold to ignore noise in the signal
                watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
                watcher.PositionChanged +=
                    new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
        
                watcher.Start();
                GPSTurnedOn = true;
            }
        }

        private void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    if (watcher.Permission == GeoPositionPermission.Denied)
                    {
                        //txtTest.Text = "Rakenduse pole õigust positsioneerimist kasutada.";
                    }
                    else
                    {
                        //txtTest.Text = "Sellel seadmel positsioneerimine ei tööta";
                    }
                    break;
                case GeoPositionStatus.Initializing:
                    GPSStatusText.Text = "Init";
                    break;
                case GeoPositionStatus.NoData:
                    GPSStatusText.Text = "X";
                    break;
                case GeoPositionStatus.Ready:
                    GPSStatusText.Text = "OK";
                    break;
                default:
                    break;
            }
        }

        private void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            GeoCoordinate geoCoordinate = e.Position.Location;

            UpdateGPSStatus(e.Position.Location.HorizontalAccuracy);

            ShowSpeed(geoCoordinate);

            if (nextSpeedCamDistance.HasValue)
            {
                if (nextSpeedCamDistance < 1000)
                {
                    string nextSpeedCamera = "Järgmine kaamera: " + String.Format("{0:0}", nextSpeedCamDistance); ;
                    textBlockNextCamera_h.Text = textBlockNextCamera_v.Text = nextSpeedCamera + "m";
                }
                else
                {
                    string nextSpeedCamera = "Järgmine kaamera: " + String.Format("{0:0.0}", nextSpeedCamDistance / 1000); ;
                    textBlockNextCamera_h.Text = textBlockNextCamera_v.Text = nextSpeedCamera + "km";
                }
            }

            bool hasCamera = HasCamera(geoCoordinate);

            if (hasCamera && previousSpeedCamDistanceValue > nextSpeedCamDistance)
            {
                this.image_h.Visibility = this.image_v.Visibility = Visibility.Visible;

                try
                {
                    if (!audibleSpeedCamAlertDone)
                    {
                        Stream streamsound = TitleContainer.OpenStream("cricket.wav");
                        SoundEffect effect = SoundEffect.FromStream(streamsound);
                        FrameworkDispatcher.Update();
                        effect.Play();

                        audibleSpeedCamAlertDone = true;
                    }
                }
                catch (Exception)
                {
                }
            }
            else if (hasCamera && previousSpeedCamDistanceValue < nextSpeedCamDistance)
            {
                audibleSpeedCamAlertDone = false;
                this.image_h.Visibility = this.image_v.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.image_h.Visibility = this.image_v.Visibility = Visibility.Collapsed;
            }
        }

        private void UpdateGPSStatus(double GPSAccuracy)
        {
            if (GPSTurnedOn)
            {
                switch (watcher.Status)
                {
                    case GeoPositionStatus.Initializing:
                        GPSStatusBar1.Fill = null;
                        GPSStatusBar2.Fill = null;
                        GPSStatusBar3.Fill = null;
                        GPSStatusBar4.Fill = null;
                        GPSStatusBar5.Fill = null;
                        GPSStatusText.Text = "Init";
                        break;
                    case GeoPositionStatus.NoData:
                        GPSStatusBar1.Fill = null;
                        GPSStatusBar2.Fill = null;
                        GPSStatusBar3.Fill = null;
                        GPSStatusBar4.Fill = null;
                        GPSStatusBar5.Fill = null;
                        GPSStatusText.Text = "X";
                        break;
                    case GeoPositionStatus.Ready:
                        if (GPSAccuracy >= 100)
                        {
                            if (GPSAccuracy > 1000)
                            {
                                GPSAccuracy = GPSAccuracy / 1000;
                                GPSStatusText.Text = GPSAccuracy.ToString("0km");
                            }
                            else
                            {
                                GPSStatusText.Text = GPSAccuracy.ToString("0m");
                            }
                            GPSStatusBar1.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar2.Fill = null;
                            GPSStatusBar3.Fill = null;
                            GPSStatusBar4.Fill = null;
                            GPSStatusBar5.Fill = null;
                        }
                        else if (GPSAccuracy >= 25 && GPSAccuracy < 100)
                        {
                            GPSStatusText.Text = GPSAccuracy.ToString("0m");
                            GPSStatusBar1.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar2.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar3.Fill = null;
                            GPSStatusBar4.Fill = null;
                            GPSStatusBar5.Fill = null;
                        }
                        else if (GPSAccuracy >= 10 && GPSAccuracy < 25)
                        {
                            GPSStatusText.Text = GPSAccuracy.ToString("0m");
                            GPSStatusBar1.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar2.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar3.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar4.Fill = null;
                            GPSStatusBar5.Fill = null;
                        }
                        else if (GPSAccuracy >= 5 && GPSAccuracy < 10)
                        {
                            GPSStatusText.Text = GPSAccuracy.ToString("0m");
                            GPSStatusBar1.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar2.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar3.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar4.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar5.Fill = null;
                        }
                        else if (GPSAccuracy < 5)
                        {
                            GPSStatusText.Text = GPSAccuracy.ToString("0m");
                            GPSStatusBar1.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar2.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar3.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar4.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                            GPSStatusBar5.Fill = (SolidColorBrush)Resources["PhoneAccentBrush"];
                        }
                        else
                        {
                            GPSStatusBar1.Fill = null;
                            GPSStatusBar2.Fill = null;
                            GPSStatusBar3.Fill = null;
                            GPSStatusBar4.Fill = null;
                            GPSStatusBar5.Fill = null;
                            GPSStatusText.Text = "X";
                        }
                        break;
                    default:
                        break;
                }
            }
            else
            {
                GPSStatusBar1.Fill = null;
                GPSStatusBar2.Fill = null;
                GPSStatusBar3.Fill = null;
                GPSStatusBar4.Fill = null;
                GPSStatusBar5.Fill = null;
                GPSStatusText.Text = "X";
            }
        }

        private void ShowSpeed(GeoCoordinate geoCoordinate)
        {
            double speed = geoCoordinate.Speed;
            if (speed.ToString() == "NaN")
            {
                textBlock_v.Visibility =  textBlock_h.Visibility = Visibility.Collapsed;
            }
            else
            {
                textBlock_v.Visibility =  textBlock_h.Visibility = Visibility.Visible;
            }

            double d = (speed*3600)/1000;
            string format = String.Format("{0:0}", d);
            textBlock_v.Text = textBlock_h.Text = format;

            if (App.IsDemo)
            {
                textBlock_v.Visibility = textBlock_h.Visibility = Visibility.Visible;
                Random random = new Random();
                int next = random.Next(0, 40);
                textBlock_v.Text = textBlock_h.Text = (70 + next).ToString();
            }
        }

        private bool HasCamera(GeoCoordinate geoCoordinate)
        {
            bool reurnValue = false;
            previousSpeedCamDistanceValue = nextSpeedCamDistance;
            nextSpeedCamDistance = null;
            foreach (XmlParser.SpeedCamContainer conteiner in App.speedCamList)
            {
                double distanceTo = geoCoordinate.GetDistanceTo(new GeoCoordinate(conteiner.GetLatitude(), conteiner.GetLongitude()));

                if (distanceTo < App.settings.SpeedCamAlertDistance)
                {
                    reurnValue =  true;

                    if (Int32.Parse(textBlock_h.Text) > conteiner.MaxSpeed)
                    {
                        SolidColorBrush myBrush = new SolidColorBrush(Colors.Red);
                        textBlock_h.Foreground = textBlock_v.Foreground = myBrush;
                    }
                    else
                    {
                        SolidColorBrush myBrush = new SolidColorBrush(Colors.White);
                        textBlock_h.Foreground = textBlock_v.Foreground = myBrush;
                    }
                }

                if (!nextSpeedCamDistance.HasValue || nextSpeedCamDistance > distanceTo)
                {
                    nextSpeedCamDistance = distanceTo;
                }
            }

            if (!reurnValue){
                SolidColorBrush myBrush = new SolidColorBrush(Colors.White);
                textBlock_h.Foreground = textBlock_v.Foreground = myBrush;
            }

            return reurnValue;
        }

        private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
        {
            UpdateOrientation(e.Orientation);
        }

        private void UpdateOrientation(PageOrientation pageOrientation)
        {
            if (pageOrientation == PageOrientation.Landscape || pageOrientation == PageOrientation.LandscapeLeft ||
                pageOrientation == PageOrientation.LandscapeRight)
            {
                ContentPanel_v.Visibility = Visibility.Collapsed;
                ContentPanel_h.Visibility = Visibility.Visible;
                GPSStatus.Margin = new Thickness(0, 0, 0, 0);
            }
            else
            {
                ContentPanel_h.Visibility = Visibility.Collapsed;
                ContentPanel_v.Visibility = Visibility.Visible;
                GPSStatus.Margin = new Thickness(0, 0, 0, 73);
            }

            if (pageOrientation == PageOrientation.Landscape || pageOrientation == PageOrientation.LandscapeLeft ||
                pageOrientation == PageOrientation.LandscapeRight)
            {
                VisualStateManager.GoToState(Panorama1, "Landscape", true);
            }
            else if (pageOrientation == PageOrientation.Portrait || pageOrientation == PageOrientation.PortraitDown ||
                     pageOrientation == PageOrientation.PortraitUp)
            {
                //VisualStateManager.GoToState(Panorama1, "Portrait", true);
                VisualStateManager.GoToState(Panorama1, "Landscape", true);
            }
        }

        // Click handler that runs when the 'Load Feed' or 'Refresh Feed' button is clicked. 
        private void updateRSS()
        {
          // WebClient is used instead of HttpWebRequest in this code sample because 
          // the implementation is simpler and easier to use, and we do not need to use 
          // advanced functionality that HttpWebRequest provides, such as the ability to send headers.
          WebClient webClient = new WebClient();

          // Subscribe to the DownloadStringCompleted event prior to downloading the RSS feed.
          webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);

          // Download the RSS feed. DownloadStringAsync was used instead of OpenStreamAsync because we do not need 
          // to leave a stream open, and we will not need to worry about closing the channel. 
          webClient.DownloadStringAsync(new System.Uri("http://www.mnt.ee/index.php?id=12388&op=rss"));
        }

        // Click handler that runs when the 'Load Feed' or 'Refresh Feed' button is clicked. 
        private void loadFeedButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
          // WebClient is used instead of HttpWebRequest in this code sample because 
          // the implementation is simpler and easier to use, and we do not need to use 
          // advanced functionality that HttpWebRequest provides, such as the ability to send headers.
          WebClient webClient = new WebClient();

          // Subscribe to the DownloadStringCompleted event prior to downloading the RSS feed.
          webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);

          // Download the RSS feed. DownloadStringAsync was used instead of OpenStreamAsync because we do not need 
          // to leave a stream open, and we will not need to worry about closing the channel. 
          webClient.DownloadStringAsync(new System.Uri("http://www.mnt.ee/index.php?id=12388&op=rss"));
        }

        // Event handler which runs after the feed is fully downloaded.
        private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
          if (e.Error != null)
          {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
              // Showing the exact error message is useful for debugging. In a finalized application, 
              // output a friendly and applicable string to the user instead. 
              MessageBox.Show(e.Error.Message);
            });
          }
          else
          {
            // Save the feed into the State property in case the application is tombstoned. 
            this.State["feed"] = e.Result;

            UpdateFeedList(e.Result);
          }
        }

        // This method determines whether the user has navigated to the application after the application was tombstoned.
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
          // First, check whether the feed is already saved in the page state.
          if (this.State.ContainsKey("feed"))
          {
            // Get the feed again only if the application was tombstoned, which means the ListBox will be empty.
            // This is because the OnNavigatedTo method is also called when navigating between pages in your application.
            // You would want to rebind only if your application was tombstoned and page state has been lost. 
            if (feedListBox.Items.Count == 0)
            {
              UpdateFeedList(State["feed"] as string);
            }
          }
        }

        // This method sets up the feed and binds it to our ListBox. 
        private void UpdateFeedList(string feedXML)
        {
          // Load the feed into a SyndicationFeed instance.
          StringReader stringReader = new StringReader(feedXML);
          XmlReader xmlReader = XmlReader.Create(stringReader);
          SyndicationFeed feed = SyndicationFeed.Load(xmlReader);

          // In Windows Phone OS 7.1, WebClient events are raised on the same type of thread they were called upon. 
          // For example, if WebClient was run on a background thread, the event would be raised on the background thread. 
          // While WebClient can raise an event on the UI thread if called from the UI thread, a best practice is to always 
          // use the Dispatcher to update the UI. This keeps the UI thread free from heavy processing.
          Deployment.Current.Dispatcher.BeginInvoke(() =>
          {
            // Bind the list of SyndicationItems to our ListBox.
            feedListBox.ItemsSource = feed.Items;

            //  loadFeedButton.Content = "Refresh Feed";
          });
        }

        // The SelectionChanged handler for the feed items 
        private void feedListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          ListBox listBox = sender as ListBox;

          if (listBox != null && listBox.SelectedItem != null)
          {
            // Get the SyndicationItem that was tapped.
            SyndicationItem sItem = (SyndicationItem)listBox.SelectedItem;

            // Set up the page navigation only if a link actually exists in the feed item.
            if (sItem.Links.Count > 0)
            {
              // Get the associated URI of the feed item.
              Uri uri = sItem.Links.FirstOrDefault().Uri;

              // Create a new WebBrowserTask Launcher to navigate to the feed item. 
              // An alternative solution would be to use a WebBrowser control, but WebBrowserTask is simpler to use. 
              WebBrowserTask webBrowserTask = new WebBrowserTask();
              webBrowserTask.Uri = uri;
              webBrowserTask.Show();
            }
          }
        }

        private void AppBarGpsButton_Click(object sender, EventArgs e)
        {
            if (GPSTurnedOn)
            {
                watcher.Stop();
                GPSTurnedOn = false;
                UpdateGPSStatus(-1);
            }
            else
            {
                watcher.Start();
                GPSTurnedOn = true;
            }
        }

        private void AppBarSettingsButton_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/SettingsPage.xaml", UriKind.Relative));
        }

        private void AppBarMenuAbout_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/AboutPage.xaml", UriKind.Relative));
        }
    }
}